# Whether to enable core-dumps when domains crash.
#(enable-dump no)
+
+# The tool used for initiating virtual TPM migration
+#(external-migration-tool '')
-def save(fd, dominfo, live):
+def save(fd, dominfo, live, dst):
write_exact(fd, SIGNATURE, "could not write guest state file: signature")
config = sxp.to_string(dominfo.sxpr())
dominfo.setName('migrating-' + domain_name)
try:
+ dominfo.migrateDevices(live, dst, 1, domain_name)
+
write_exact(fd, pack("!i", len(config)),
"could not write guest state file: config len")
write_exact(fd, config, "could not write guest state file: config")
log.debug("Suspending %d ...", dominfo.getDomid())
dominfo.shutdown('suspend')
dominfo.waitForShutdown()
+ dominfo.migrateDevices(live, dst, 2, domain_name)
log.info("Domain %d suspended.", dominfo.getDomid())
+ dominfo.migrateDevices(live, dst, 3, domain_name)
tochild.write("done\n")
tochild.flush()
log.debug('Written done')
if dominfo.getDomid() == PRIV_DOMAIN:
raise XendError("Cannot migrate privileged domain %i" % domid)
+ """ The following call may raise a XendError exception """
+ dominfo.testMigrateDevices(live, dst)
+
if port == 0:
port = xroot.get_xend_relocation_port()
try:
raise XendError("can't connect: %s" % err[1])
sock.send("receive\n")
- sock.recv(80)
- XendCheckpoint.save(sock.fileno(), dominfo, live)
+ sock.recv(80)
+ XendCheckpoint.save(sock.fileno(), dominfo, live, dst)
def domain_save(self, domid, dst):
fd = os.open(dst, os.O_WRONLY | os.O_CREAT | os.O_TRUNC)
try:
# For now we don't support 'live checkpoint'
- return XendCheckpoint.save(fd, dominfo, False)
+ return XendCheckpoint.save(fd, dominfo, False, dst)
finally:
os.close(fd)
except OSError, ex:
if self.image:
self.image.createDeviceModel()
+ ## public:
+
+ def testMigrateDevices(self, live, dst):
+ """ Notify all device about intention of migration
+ @raise: XendError for a device that cannot be migrated
+ """
+ for (n, c) in self.info['device']:
+ rc = self.migrateDevice(n, c, live, dst, 0)
+ if rc != 0:
+ raise XendError("Device of type '%s' refuses migration." % n)
+
+ def migrateDevices(self, live, dst, step, domName=''):
+ """Notify the devices about migration
+ """
+ ctr = 0
+ try:
+ for (n, c) in self.info['device']:
+ self.migrateDevice(n, c, live, dst, step, domName)
+ ctr = ctr + 1
+ except:
+ for (n, c) in self.info['device']:
+ if ctr == 0:
+ step = step - 1
+ ctr = ctr - 1
+ self.recoverMigrateDevice(n, c, live, dst, step, domName)
+ raise
+
+ def migrateDevice(self, deviceClass, deviceConfig, live, dst, step, domName=''):
+ return self.getDeviceController(deviceClass).migrate(deviceConfig, live, dst, step, domName)
+
+ def recoverMigrateDevice(self, deviceClass, deviceConfig, live, dst, step, domName=''):
+ return self.getDeviceController(deviceClass).recover_migrate(deviceConfig, live, dst, step, domName)
def waitForDevices(self):
"""Wait for this domain's configured devices to connect.
server (deprecated)."""
xend_unix_server_default = 'no'
+ """Default external migration tool """
+ external_migration_tool_default = ''
+
"""Default path the unix-domain server listens at."""
xend_unix_path_default = '/var/lib/xend/xend-socket'
else:
return None
+ def get_external_migration_tool(self):
+ """@return the name of the tool to handle virtual TPM migration."""
+ return self.get_config_value('external-migration-tool', self.external_migration_tool_default)
def get_enable_dump(self):
return self.get_config_bool('enable-dump', 'no')
raise NotImplementedError()
+ def migrate(self, deviceConfig, live, dst, step, domName):
+ """ Migration of a device. The 'live' parameter indicates
+ whether the device is live-migrated (live=1). 'dst' then gives
+ the hostname of the machine to migrate to.
+ This function is called for 4 steps:
+ If step == 0: Check whether the device is ready to be migrated
+ or can at all be migrated; return a '-1' if
+ the device is NOT ready, a '0' otherwise. If it is
+ not ready ( = not possible to migrate this device),
+ migration will not take place.
+ step == 1: Called immediately after step 0; migration
+ of the kernel has started;
+ step == 2: Called after the suspend has been issued
+ to the domain and the domain is not scheduled anymore.
+ Synchronize with what was started in step 1, if necessary.
+ Now the device should initiate its transfer to the
+ given target. Since there might be more than just
+ one device initiating a migration, this step should
+ put the process performing the transfer into the
+ background and return immediately to achieve as much
+ concurrency as possible.
+ step == 3: Synchronize with the migration of the device that
+ was initiated in step 2.
+ Make sure that the migration has finished and only
+ then return from the call.
+ """
+ return 0
+
+
+ def recover_migrate(self, deviceConfig, list, dst, step, domName):
+ """ Recover from device migration. The given step was the
+ last one that was successfully executed.
+ """
+ return 0
+
def getDomid(self):
"""Stub to {@link XendDomainInfo.getDomid}, for use by our
from xen.xend import sxp
from xen.xend.XendLogging import log
+from xen.xend.XendError import XendError
+from xen.xend import XendRoot
from xen.xend.server.DevController import DevController
+import os
+import re
+
+
+xroot = XendRoot.instance()
+
class TPMifController(DevController):
"""TPM interface controller. Handles all TPM devices for a domain.
result.append(['instance', instance])
return result
+
+ def migrate(self, deviceConfig, live, dst, step, domName):
+ """@see DevContoller.migrate"""
+ if live:
+ tool = xroot.get_external_migration_tool()
+ if tool != '':
+ log.info("Request to live-migrate device to %s. step=%d.",
+ dst, step)
+
+ if step == 0:
+ """Assuming for now that everything is ok and migration
+ with the given tool can proceed.
+ """
+ return 0
+ else:
+ fd = os.popen("%s -type vtpm -step %d -host %s -domname %s" %
+ (tool, step, dst, domName),
+ 'r')
+ for line in fd.readlines():
+ mo = re.search('Error', line)
+ if mo:
+ raise XendError("vtpm: Fatal error in migration step %d." %
+ step)
+ return 0
+ else:
+ log.debug("External migration tool not in configuration.")
+ return -1
+ return 0
+
+ def recover_migrate(self, deviceConfig, live, dst, step, domName):
+ """@see DevContoller.recover_migrate"""
+ if live:
+ tool = xroot.get_external_migration_tool()
+ if tool != '':
+ log.info("Request to recover live-migrated device. last good step=%d.",
+ step)
+ fd = os.popen("%s -type vtpm -step %d -host %s -domname %s -recover" %
+ (tool, step, dst, domName),
+ 'r')
+ return 0